#include <gtk/gtk.h>
#include <gdk/gdkkeysyms.h>

#include "common.h"

/**
 * 说明：
 * GtkTexView 构件常常用来显示和编辑多行的文本。
 * GtkTexBuffer 构件也是由 MVC 原理设计的，代表model元素，常用于处理文本数据；而GtkTextView就是显示(view)元素。
 * GtkTextTag 则是一种被用于文本的属性。
 * GtkTextIter 则是代表了两个字符之间的空隙。文本的排版操作多用 iterators。
 */

void simple_demo(GtkWidget *window);

void on_textBuffer_changed(GtkTextBuffer *buffer, gpointer *statubar);
void on_textBuffer_mark_set(GtkTextBuffer *buffer, const GtkTextIter *new_location, GtkTextMark *mark, gpointer data);
void lines_and_col_demo(GtkWidget *window);

gboolean on_window_key_pressed(GtkWidget *window, GdkEventKey *event, GtkTextBuffer *buffer);
void search_and_highlight_demo(GtkWidget *window);  /*突显文本中与选中内容一样的内容*/

int main( int argc, char *argv[]){
    GtkWidget *window;
    GdkColor  color_ = {0x0, 0x50, 0x50, 0x50};

    gtk_init(&argc, &argv);

    /* window */
    window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
    gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
#if 0
    gtk_window_fullscreen(GTK_WINDOW(window));              /*设置全屏*/
#else
    gtk_widget_set_size_request (window, 750, 550);         /*设置窗口大小*/
    gtk_window_set_resizable(GTK_WINDOW(window), FALSE);    /*设置窗口不能拉伸*/
#endif
    gtk_window_set_title(GTK_WINDOW(window), TITLE);
//    gtk_container_set_border_width(GTK_CONTAINER(window), 15);  /*设置容器边界大小*/
    gtk_widget_modify_bg(window, GTK_STATE_NORMAL, &color_); /*设置为背景颜色*/
//    gtk_window_set_decorated(GTK_WINDOW(window), FALSE);	/*设置不提供装饰*/
    GTK_WINDOW(window)->allow_shrink = TRUE;

    /* test */
//    simple_demo(window);
//    lines_and_col_demo(window);
    search_and_highlight_demo(window);

    /* signal setting */
    g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(gtk_main_quit), NULL);
    gtk_widget_show_all(window);
    gtk_main();

    return 0;
}

void search_and_highlight_demo(GtkWidget *window)
{
    GtkWidget *textView;
    GtkWidget *vbox;
    GtkTextBuffer *buffer;

    textView = gtk_text_view_new();
    gtk_widget_add_events(textView, GDK_BUTTON_PRESS_MASK);

    buffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(textView));
    gtk_text_buffer_create_tag(buffer, "yellow_bg", "background", "yellow", NULL);

    vbox = gtk_vbox_new(FALSE, 0);
    gtk_container_add(GTK_CONTAINER(window), vbox);
    gtk_box_pack_start(GTK_BOX(vbox), textView, TRUE, TRUE, 0);

    g_signal_connect(G_OBJECT(window), "key-press-event", G_CALLBACK(on_window_key_pressed), buffer);
}

gboolean on_window_key_pressed(GtkWidget *window, GdkEventKey *event, GtkTextBuffer *buffer)
{
    GtkTextIter startSelIter, endSelIter;
    GtkTextIter startFindIter, endFindIter;
    GtkTextIter startMatchIter, endMatchIter;
    gboolean selected;
    gchar *text;

    if ((event->type == GDK_KEY_PRESS)
            && (event->state & GDK_CONTROL_MASK)) {
        switch (event->keyval) {
        case GDK_m:
            selected = gtk_text_buffer_get_selection_bounds(buffer, &startSelIter, &endSelIter); /*获取选中的文本的起始和终点位置*/
            if (selected) {
                gtk_text_buffer_get_start_iter(buffer, &startFindIter); /*获取文本缓冲区的起始位置*/
                gtk_text_buffer_get_end_iter(buffer, &endFindIter);     /*获取文本缓冲区的终点位置*/
                gtk_text_buffer_remove_tag_by_name(buffer, "yellow_bg", &startFindIter, &endFindIter);

                text = (gchar *)gtk_text_buffer_get_text(buffer, &startSelIter, &endSelIter, FALSE); /*获取选中文本的内容*/

                while (gtk_text_iter_forward_search(&startFindIter, text,
                                                    GTK_TEXT_SEARCH_TEXT_ONLY | GTK_TEXT_SEARCH_VISIBLE_ONLY,
                                                    &startMatchIter, &endMatchIter, NULL)) {
                    gtk_text_buffer_apply_tag_by_name(buffer, "yellow_bg", &startMatchIter, &endMatchIter);
                    int offset = gtk_text_iter_get_offset(&endMatchIter);
                    gtk_text_buffer_get_iter_at_offset(buffer, &startFindIter, offset);
                }
                g_free(text);
            }
            break;
        case GDK_r:
            gtk_text_buffer_get_start_iter(buffer, &startFindIter);
            gtk_text_buffer_get_end_iter(buffer, &endFindIter);
            gtk_text_buffer_remove_tag_by_name(buffer, "yellow_bg", &startFindIter, &endFindIter);
            break;
        default:
            break;
        }
    }

}

void lines_and_col_demo(GtkWidget *window)
{
    GtkWidget *vbox;
    GtkWidget *textView;
    GtkWidget *statusbar;
    GtkWidget *toolbar;
    GtkToolItem *exitToolItem;
    GtkTextBuffer *textBuffer;

    exitToolItem = gtk_tool_button_new_from_stock(GTK_STOCK_QUIT);
    GTK_WIDGET_UNSET_FLAGS(GTK_WIDGET(exitToolItem), GTK_CAN_FOCUS);   /*取消默认锁定*/
    g_signal_connect(G_OBJECT(exitToolItem), "clicked", G_CALLBACK(gtk_main_quit), NULL);

    toolbar = gtk_toolbar_new();
    gtk_toolbar_set_style(GTK_TOOLBAR(toolbar), GTK_TOOLBAR_ICONS);
    gtk_toolbar_insert(GTK_TOOLBAR(toolbar), exitToolItem, -1);

    textView = gtk_text_view_new();

    statusbar = gtk_statusbar_new();

    textBuffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(textView));
    g_signal_connect(G_OBJECT(textBuffer), "changed", G_CALLBACK(on_textBuffer_changed), statusbar);
    g_signal_connect_object(G_OBJECT(textBuffer), "mark_set", G_CALLBACK(on_textBuffer_mark_set), statusbar, 0);

    vbox = gtk_vbox_new(FALSE, 0);
    gtk_container_add(GTK_CONTAINER(window), vbox);
    gtk_box_pack_start(GTK_BOX(vbox), toolbar, FALSE, FALSE, 5);
    gtk_box_pack_start(GTK_BOX(vbox), textView, TRUE, TRUE, 0);
    gtk_box_pack_start(GTK_BOX(vbox), statusbar, FALSE, FALSE, 0);

    gtk_widget_grab_focus(textView); //将焦点移到textView部件上， 该函数需要放在部件设置好之后调用。

    on_textBuffer_changed(textBuffer, (gpointer)statusbar);
}

void on_textBuffer_mark_set(GtkTextBuffer *buffer, const GtkTextIter *new_location, GtkTextMark *mark, gpointer data)
{
    on_textBuffer_changed(buffer, (gpointer)data);
}

void on_textBuffer_changed(GtkTextBuffer *buffer, gpointer *statusbar)
{
    gchar *msg;
    gint row, col;
    GtkTextIter iter;

    gtk_statusbar_pop(GTK_STATUSBAR(statusbar), 0);
    gtk_text_buffer_get_iter_at_mark(buffer, &iter, gtk_text_buffer_get_insert(buffer));

    row = gtk_text_iter_get_line(&iter);
    col = gtk_text_iter_get_line_offset(&iter);

    msg = g_strdup_printf("Col %d Ln %d", col+1, row+1);

    gtk_statusbar_push(GTK_STATUSBAR(statusbar), 0, msg);

    g_free(msg);
}

void simple_demo(GtkWidget *window)
{
    GtkWidget *textView;
    GtkWidget *vbox;

    GtkTextBuffer *textBuffer;
    GtkTextIter iter;

    textView = gtk_text_view_new();

    textBuffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(textView));
    gtk_text_buffer_create_tag(textBuffer, "gap", "pixels_above_lines", 30, NULL);
    gtk_text_buffer_create_tag(textBuffer, "lmarg", "left_margin", 5, NULL);
    gtk_text_buffer_create_tag(textBuffer, "blue_fg", "foreground", "blue", NULL);
    gtk_text_buffer_create_tag(textBuffer, "gray_bg", "background", "gray", NULL);
    gtk_text_buffer_create_tag(textBuffer, "italic", "style", PANGO_STYLE_ITALIC, NULL);
    gtk_text_buffer_create_tag(textBuffer, "bold", "weight", PANGO_WEIGHT_BOLD, NULL);

    gtk_text_buffer_get_iter_at_offset(textBuffer, &iter, 0);

    gtk_text_buffer_insert(textBuffer, &iter, "Plain Text\n", -1);
    gtk_text_buffer_insert_with_tags_by_name(textBuffer, &iter, "Colored Text\n", -1, "blue_fg", "lmarg", NULL);
    gtk_text_buffer_insert_with_tags_by_name(textBuffer, &iter, "Text with colored background\n", -1, "lmarg", "gray_bg", NULL);
    gtk_text_buffer_insert_with_tags_by_name(textBuffer, &iter, "Text in italics\n", -1, "italic", "lmarg", NULL);
    gtk_text_buffer_insert_with_tags_by_name(textBuffer, &iter, "Bold text\n", -1, "bold", "lmarg", NULL);


    vbox = gtk_vbox_new(FALSE, 0);
    gtk_box_pack_start(GTK_BOX(vbox), textView, TRUE, TRUE, 0);
    gtk_container_add(GTK_CONTAINER(window), vbox);
}
